﻿//bp Soldatov!DriverEntry
//bp Soldatov!FileDiskDeviceControl
//bp Soldatov!ReadWrite_IRPhandler
//bp Soldatov!FileDiskThread
//bp Soldatov!FileDiskCreateDevice
#include <ntddk.h>
#include <ntdddisk.h>
#include <ntddstor.h>
#include <ntverp.h>
#include <ntddcdrm.h>
#include <ntddvol.h>
#include <mountmgr.h>
#include <mountdev.h>
#include "init.h"
#include "Encryption_Key.h"
#include "Encryption_AES.h"
#include "Encryption_Blocks.h"


#define DOS_DEVISE_NAME L"\\Device\\MYDEVICE"
#define DOS_DEVISE_NAME_FUNC L"\\Device\\FuncObj"
//#define	SYM_LINK_DISK	L"\\DosDevices\\MyVirtualDiskLink"
#define	SYM_LINK_FUNC	L"\\DosDevices\\MyFDOLink"
// Предварительные объявления функций:
VOID FileDiskThread(IN PVOID Context);
NTSTATUS FileDiskCreateClose(IN PDEVICE_OBJECT   DeviceObject, IN PIRP Irp);
NTSTATUS FileDiskCreateDevice(IN PDEVICE_OBJECT   DeviceObject);
NTSTATUS FileDiskOpenFile(IN PDEVICE_OBJECT   DeviceObject, IN PIRP Irp);
NTSTATUS FileDiskDeviceControl(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp);
VOID     UnloadRoutine(IN PDRIVER_OBJECT DriverObject);
NTSTATUS ReadWrite_IRPhandler(IN PDEVICE_OBJECT fdo, IN PIRP Irp);
NTSTATUS Create_File_IRPprocessing(IN PDEVICE_OBJECT fdo, IN PIRP Irp);
//NTSTATUS Close_HandleIRPprocessing(IN PDEVICE_OBJECT fdo, IN PIRP Irp);
#pragma code_seg("INIT")

extern "C"

NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath)
{
	NTSTATUS status = STATUS_SUCCESS;
	UNICODE_STRING      device_name;
	PDEVICE_OBJECT      device_object;
	PFUNC_DEV_OBJ   device_extension;
#if DBG
	DbgPrint("=Example= In DriverEntry.");
	DbgPrint("=Example= RegistryPath = %ws.", RegistryPath->Buffer);
#endif
	DriverObject->DriverUnload = UnloadRoutine;
	DriverObject->MajorFunction[IRP_MJ_CREATE] = FileDiskCreateClose;
	DriverObject->MajorFunction[IRP_MJ_CLOSE] = FileDiskCreateClose;
	DriverObject->MajorFunction[IRP_MJ_CLEANUP] = Create_File_IRPprocessing;
	DriverObject->MajorFunction[IRP_MJ_READ] = ReadWrite_IRPhandler;
	DriverObject->MajorFunction[IRP_MJ_WRITE] = ReadWrite_IRPhandler;
	DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = FileDiskDeviceControl;

	RtlInitUnicodeString(&device_name, DOS_DEVISE_NAME_FUNC);

	status = IoCreateDevice(
		DriverObject,
		sizeof(FUNC_DEV_OBJ),
		&device_name,
		FILE_DEVICE_UNKNOWN,
		0,
		FALSE,
		&device_object
		);
	if (!NT_SUCCESS(status))
	{
		return status;
	}
	device_extension = (PFUNC_DEV_OBJ)device_object->DeviceExtension;
	device_object->Flags |= DO_DIRECT_IO;

	UNICODE_STRING      Teststr;

	RtlInitUnicodeString(&Teststr, SYM_LINK_FUNC);
	device_extension->symbolic_link.Buffer = (PWCH)ExAllocatePool(NonPagedPool, Teststr.Length);
	device_extension->symbolic_link.Length = Teststr.Length;
	device_extension->symbolic_link.MaximumLength = Teststr.MaximumLength;
	RtlCopyUnicodeString(&device_extension->symbolic_link, &Teststr);
	status = IoCreateSymbolicLink(&device_extension->symbolic_link, &device_name);

	device_extension->device_name.Buffer = (PWCH)ExAllocatePool(NonPagedPool, device_name.Length);
	device_extension->device_name.Length = device_name.Length;
	device_extension->device_name.MaximumLength = device_name.MaximumLength;
	RtlCopyUnicodeString(&device_extension->device_name, &device_name);


	//status = FileDiskCreateDevice(DriverObject);

	return status;
}

#pragma code_seg() // end INIT section


NTSTATUS CompleteIrp(PIRP Irp, NTSTATUS status, ULONG info)
{
	Irp->IoStatus.Status = status;
	Irp->IoStatus.Information = info;
	IoCompleteRequest(Irp, IO_NO_INCREMENT);
	return status;
}

NTSTATUS ReadWrite_IRPhandler(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
{
	PDEVICE_EXTENSION   device_extension;
	PIO_STACK_LOCATION  io_stack;

	device_extension = (PDEVICE_EXTENSION)DeviceObject->DeviceExtension;

	//if (!device_extension->media_in_device)
	//{
	//	Irp->IoStatus.Status = STATUS_NO_MEDIA_IN_DEVICE;
	//	Irp->IoStatus.Information = 0;

	//	IoCompleteRequest(Irp, IO_NO_INCREMENT);

	//	return STATUS_NO_MEDIA_IN_DEVICE;
	//}

	io_stack = IoGetCurrentIrpStackLocation(Irp);

	if (io_stack->Parameters.Read.Length == 0)
	{
		Irp->IoStatus.Status = STATUS_SUCCESS;
		Irp->IoStatus.Information = 0;

		IoCompleteRequest(Irp, IO_NO_INCREMENT);

		return STATUS_SUCCESS;
	}

	IoMarkIrpPending(Irp);

	ExInterlockedInsertTailList(
		&device_extension->list_head,
		&Irp->Tail.Overlay.ListEntry,
		&device_extension->list_lock
		);

	KeSetEvent(
		&device_extension->request_event,
		(KPRIORITY)0,
		FALSE
		);

	return STATUS_PENDING;
}

NTSTATUS FileDiskCreateClose(IN PDEVICE_OBJECT   DeviceObject, IN PIRP Irp)
{
	PAGED_CODE();

	Irp->IoStatus.Status = STATUS_SUCCESS;
	Irp->IoStatus.Information = FILE_OPENED;

	IoCompleteRequest(Irp, IO_NO_INCREMENT);

	return STATUS_SUCCESS;
}

NTSTATUS Create_File_IRPprocessing(IN PDEVICE_OBJECT fdo, IN PIRP Irp)
{
	PIO_STACK_LOCATION IrpStack = IoGetCurrentIrpStackLocation(Irp);
	// Задаем печать отладочных сообщений - если сборка отладочная
#if DBG
	DbgPrint("-Example- Create File is %ws",
		&(IrpStack->FileObject->FileName.Buffer));
#endif
	return CompleteIrp(Irp, STATUS_SUCCESS, 0); // Успешное завершение
}

//NTSTATUS Close_HandleIRPprocessing(IN PDEVICE_OBJECT fdo, IN PIRP Irp)
//{
//#if DBG
//	// Задаем печать отладочных сообщений - если сборка отладочная
//	DbgPrint("-Example- In Close handler.");
//#endif
//	return CompleteIrp(Irp, STATUS_SUCCESS, 0);// Успешное завершение
//}

NTSTATUS FileDiskDeviceControl(IN PDEVICE_OBJECT  DeviceObject, IN PIRP Irp)
{
	PDEVICE_EXTENSION   device_extension;
	PIO_STACK_LOCATION  io_stack;
	NTSTATUS            status;

	device_extension = (PDEVICE_EXTENSION)DeviceObject->DeviceExtension;

	io_stack = IoGetCurrentIrpStackLocation(Irp);


#if DBG
	DbgPrint("-Example- In DeviceControlRoutine (fdo= %X)\n", DeviceObject);
	DbgPrint("-Example- DeviceIoControl: IOCTL %x.", io_stack->Parameters.DeviceIoControl.IoControlCode);

#endif

	//if (!device_extension->media_in_device &&
	//	io_stack->Parameters.DeviceIoControl.IoControlCode !=
	//	IOCTL_FILE_DISK_MOUNT)
	//{
	//	Irp->IoStatus.Status = STATUS_NO_MEDIA_IN_DEVICE;
	//	Irp->IoStatus.Information = 0;

	//	IoCompleteRequest(Irp, IO_NO_INCREMENT);

	//	return STATUS_NO_MEDIA_IN_DEVICE;
	//}

	if (DeviceObject->Type != FILE_DEVICE_DISK && io_stack->Parameters.DeviceIoControl.IoControlCode != IOCTL_FILE_DISK_MOUNT)
	{
		Irp->IoStatus.Status = STATUS_NO_MEDIA_IN_DEVICE;
		Irp->IoStatus.Information = 0;

		IoCompleteRequest(Irp, IO_NO_INCREMENT);

		return STATUS_NO_MEDIA_IN_DEVICE;
	}


	switch (io_stack->Parameters.DeviceIoControl.IoControlCode)
	{
	case IOCTL_FILE_DISK_MOUNT:
	{


		//device_extension->media_in_device = true;
		status = FileDiskCreateDevice(DeviceObject);
		//status = STATUS_SUCCESS;
		break;
	}

	case IOCTL_FILE_DISK_UNMOUNT:
	{
		IoMarkIrpPending(Irp);

		ExInterlockedInsertTailList(
			&device_extension->list_head,
			&Irp->Tail.Overlay.ListEntry,
			&device_extension->list_lock
			);

		KeSetEvent(
			&device_extension->request_event,
			(KPRIORITY)0,
			FALSE
			);

		status = STATUS_PENDING;

		break;
	}
	case IOCTL_DISK_CHECK_VERIFY:
	case IOCTL_CDROM_CHECK_VERIFY:
	case IOCTL_STORAGE_CHECK_VERIFY:
	case IOCTL_STORAGE_CHECK_VERIFY2:
	{
		status = STATUS_SUCCESS;
		Irp->IoStatus.Information = 0;
		break;
	}

	case IOCTL_DISK_GET_DRIVE_GEOMETRY:
	case IOCTL_CDROM_GET_DRIVE_GEOMETRY:
	{
		PDISK_GEOMETRY  disk_geometry;


		if (io_stack->Parameters.DeviceIoControl.OutputBufferLength <
			sizeof(DISK_GEOMETRY))
		{
			status = STATUS_BUFFER_TOO_SMALL;
			Irp->IoStatus.Information = 0;
			break;
		}

		disk_geometry = (PDISK_GEOMETRY)Irp->AssociatedIrp.SystemBuffer;

		disk_geometry->Cylinders.QuadPart = device_extension->DiskInfo.DiskGeometryEx.DiskSize.QuadPart / device_extension->DiskInfo.DiskGeometryEx.Geometry.BytesPerSector / 32 / 2;
		disk_geometry->MediaType = FixedMedia;
		disk_geometry->TracksPerCylinder = device_extension->DiskInfo.DiskGeometryEx.Geometry.TracksPerCylinder;
		disk_geometry->SectorsPerTrack = device_extension->DiskInfo.DiskGeometryEx.Geometry.SectorsPerTrack;
		disk_geometry->BytesPerSector = device_extension->DiskInfo.DiskGeometryEx.Geometry.BytesPerSector;

		status = STATUS_SUCCESS;
		Irp->IoStatus.Information = sizeof(DISK_GEOMETRY);

		break;
	}

	case IOCTL_DISK_GET_LENGTH_INFO:
	{
		PGET_LENGTH_INFORMATION get_length_information;

		if (io_stack->Parameters.DeviceIoControl.OutputBufferLength <
			sizeof(GET_LENGTH_INFORMATION))
		{
			status = STATUS_BUFFER_TOO_SMALL;
			Irp->IoStatus.Information = 0;
			break;
		}

		get_length_information = (PGET_LENGTH_INFORMATION)Irp->AssociatedIrp.SystemBuffer;

		get_length_information->Length.QuadPart = device_extension->DiskInfo.DiskGeometryEx.DiskSize.QuadPart;

		status = STATUS_SUCCESS;
		Irp->IoStatus.Information = sizeof(GET_LENGTH_INFORMATION);

		break;
	}

	case IOCTL_DISK_GET_PARTITION_INFO:
	{
		PPARTITION_INFORMATION  partition_information;

		if (io_stack->Parameters.DeviceIoControl.OutputBufferLength <
			sizeof(PARTITION_INFORMATION))
		{
			status = STATUS_BUFFER_TOO_SMALL;
			Irp->IoStatus.Information = 0;
			break;
		}

		partition_information = (PPARTITION_INFORMATION)Irp->AssociatedIrp.SystemBuffer;

		partition_information->StartingOffset.QuadPart = 0;
		partition_information->PartitionLength.QuadPart = device_extension->DiskInfo.DiskGeometryEx.DiskSize.QuadPart;
		partition_information->HiddenSectors = 1;
		partition_information->PartitionNumber = 0;
		partition_information->PartitionType = 0;
		partition_information->BootIndicator = FALSE;
		partition_information->RecognizedPartition = FALSE;
		partition_information->RewritePartition = FALSE;

		status = STATUS_SUCCESS;
		Irp->IoStatus.Information = sizeof(PARTITION_INFORMATION);

		break;
	}

	case IOCTL_DISK_GET_PARTITION_INFO_EX:
	{
		PPARTITION_INFORMATION_EX   partition_information_ex;

		if (io_stack->Parameters.DeviceIoControl.OutputBufferLength <
			sizeof(PARTITION_INFORMATION_EX))
		{
			status = STATUS_BUFFER_TOO_SMALL;
			Irp->IoStatus.Information = 0;
			break;
		}

		partition_information_ex = (PPARTITION_INFORMATION_EX)Irp->AssociatedIrp.SystemBuffer;

		partition_information_ex->PartitionStyle = PARTITION_STYLE_MBR;
		partition_information_ex->StartingOffset.QuadPart = 0;
		partition_information_ex->PartitionLength.QuadPart = device_extension->DiskInfo.DiskGeometryEx.DiskSize.QuadPart;
		partition_information_ex->PartitionNumber = 0;
		partition_information_ex->RewritePartition = FALSE;
		partition_information_ex->Mbr.PartitionType = 0;
		partition_information_ex->Mbr.BootIndicator = FALSE;
		partition_information_ex->Mbr.RecognizedPartition = FALSE;
		partition_information_ex->Mbr.HiddenSectors = 1;

		status = STATUS_SUCCESS;
		Irp->IoStatus.Information = sizeof(PARTITION_INFORMATION_EX);

		break;
	}

	case IOCTL_DISK_IS_WRITABLE:
	{
		status = STATUS_SUCCESS;
		Irp->IoStatus.Information = 0;
		break;
	}

	case IOCTL_DISK_MEDIA_REMOVAL:
	case IOCTL_STORAGE_MEDIA_REMOVAL:
	{
		status = STATUS_SUCCESS;
		Irp->IoStatus.Information = 0;
		break;
	}
	case IOCTL_DISK_SET_PARTITION_INFO:
	{


		if (io_stack->Parameters.DeviceIoControl.InputBufferLength <
			sizeof(SET_PARTITION_INFORMATION))
		{
			status = STATUS_INVALID_PARAMETER;
			Irp->IoStatus.Information = 0;
			break;
		}

		status = STATUS_SUCCESS;
		Irp->IoStatus.Information = 0;

		break;
	}

	case IOCTL_DISK_VERIFY:
	{
		PVERIFY_INFORMATION verify_information;

		if (io_stack->Parameters.DeviceIoControl.InputBufferLength <
			sizeof(VERIFY_INFORMATION))
		{
			status = STATUS_INVALID_PARAMETER;
			Irp->IoStatus.Information = 0;
			break;
		}

		verify_information = (PVERIFY_INFORMATION)Irp->AssociatedIrp.SystemBuffer;

		status = STATUS_SUCCESS;
		Irp->IoStatus.Information = verify_information->Length;

		break;
	}

	default:
	{
		KdPrint((
			"FileDisk: Unknown IoControlCode %#x\n",
			io_stack->Parameters.DeviceIoControl.IoControlCode
			));

		status = STATUS_INVALID_DEVICE_REQUEST;
		Irp->IoStatus.Information = 0;
	}
	}

	if (status != STATUS_PENDING)
	{
		Irp->IoStatus.Status = status;

		IoCompleteRequest(Irp, IO_NO_INCREMENT);
	}

	return status;
}

#pragma code_seg("PAGE")
VOID UnloadRoutine(IN PDRIVER_OBJECT pDriverObject)
{
	PDEVICE_OBJECT	pNextDevObj;
	PDEVICE_EXTENSION dx;
	PFUNC_DEV_OBJ fd;
	pNextDevObj = pDriverObject->DeviceObject;
	while (pNextDevObj != NULL)
	{

		if (pNextDevObj->Type == FILE_DEVICE_DISK)
		{
			dx = (PDEVICE_EXTENSION)pNextDevObj->DeviceExtension;
			pNextDevObj = pDriverObject->DeviceObject->NextDevice;

			if (dx->device_name.Buffer != NULL)
				ExFreePool(dx->device_name.Buffer);
			if (dx->DiskInfo.FilePath.Buffer != NULL)
				ExFreePool(dx->DiskInfo.FilePath.Buffer);
			if (dx->file_handle != NULL)
				ZwClose(dx->file_handle);

			dx->terminate_thread = TRUE;

			KeSetEvent(
				&dx->request_event,
				(KPRIORITY)0,
				FALSE
				);

			KeWaitForSingleObject(
				dx->thread_pointer,
				Executive,
				KernelMode,
				FALSE,
				NULL
				);

		}
		//IoDeleteSymbolicLink(&((PDEVICE_EXTENSION)pDriverObject->DeviceObject->DeviceExtension)->SymbolicLink);
		else
		{
			fd = (PFUNC_DEV_OBJ)pDriverObject->DeviceObject->DeviceExtension;
			if (fd->device_name.Buffer != NULL)
				ExFreePool(fd->device_name.Buffer);
			if (fd->symbolic_link.Buffer != NULL)
			{
				IoDeleteSymbolicLink(&fd->symbolic_link);
				ExFreePool(fd->symbolic_link.Buffer);
			}

			pNextDevObj = pDriverObject->DeviceObject->NextDevice;
		}
		IoDeleteDevice(pDriverObject->DeviceObject);
	}
}

NTSTATUS FileDiskCreateDevice(IN PDEVICE_OBJECT  DeviceObject)
{
	UNICODE_STRING      device_name;
	NTSTATUS            status;
	PDEVICE_OBJECT      device_object;
	PDEVICE_EXTENSION   device_extension;
	HANDLE              thread_handle;


#if DBG
	DbgPrint("=Example= In FileDiskCreateDevice.");
#endif
	RtlInitUnicodeString(&device_name, DOS_DEVISE_NAME); 	//RtlInitUnicodeString(&device_name, device_name_buffer);

	//RtlInitUnicodeString(&sddl, _T("D:P(A;;GA;;;SY)(A;;GA;;;BA)(A;;GA;;;BU)"));

	status = IoCreateDevice(
		DeviceObject->DriverObject,
		sizeof(DEVICE_EXTENSION),
		&device_name,
		FILE_DEVICE_DISK,
		0,
		FALSE,
		&device_object
		);

	if (!NT_SUCCESS(status))
	{
		return status;
	}

	device_object->Flags |= DO_DIRECT_IO;


	device_extension = (PDEVICE_EXTENSION)device_object->DeviceExtension;
	UNICODE_STRING      Teststr;
	RtlInitUnicodeString(&Teststr, L"\\??\\C:\\MySoldatov.txt");
	device_extension->DiskInfo.FilePath.Buffer = (PWCH)ExAllocatePool(PagedPool, Teststr.Length);
	device_extension->DiskInfo.FilePath.Length = Teststr.Length;
	device_extension->DiskInfo.FilePath.MaximumLength = Teststr.MaximumLength;
	RtlCopyUnicodeString(&device_extension->DiskInfo.FilePath, &Teststr);

	// Создаем символьную ссылку
	//RtlInitUnicodeString(&Teststr, SYM_LINK_DISK);
	//device_extension->SymbolicLink.Buffer = (PWCH)ExAllocatePool(PagedPool, Teststr.Length);
	//device_extension->SymbolicLink.Length = Teststr.Length;
	//device_extension->SymbolicLink.MaximumLength = Teststr.MaximumLength;
	//RtlCopyUnicodeString(&device_extension->SymbolicLink, &Teststr);
	//status = IoCreateSymbolicLink(&device_extension->SymbolicLink, &device_name);

	device_extension->DiskInfo.DiskGeometryEx.Geometry.BytesPerSector = 512;
	device_extension->DiskInfo.DiskGeometryEx.Geometry.SectorsPerTrack = 32;     // Using Ramdisk value
	device_extension->DiskInfo.DiskGeometryEx.Geometry.TracksPerCylinder = 2;    // Using Ramdisk value
	device_extension->DiskInfo.DiskGeometryEx.DiskSize.QuadPart = 102400000;
	device_extension->DiskInfo.DiskGeometryEx.Geometry.Cylinders.QuadPart = device_extension->DiskInfo.DiskGeometryEx.DiskSize.QuadPart / 512 / 32 / 2;
	device_extension->DiskInfo.DiskGeometryEx.Geometry.MediaType = FixedMedia;

	//device_extension->media_in_device = FALSE;// FALSE;

	InitializeListHead(&device_extension->list_head);

	KeInitializeSpinLock(&device_extension->list_lock);

	KeInitializeEvent(
		&device_extension->request_event,
		SynchronizationEvent,
		FALSE
		);

	device_extension->terminate_thread = FALSE;

	status = PsCreateSystemThread(
		&thread_handle,
		STANDARD_RIGHTS_ALL,
		NULL,
		NULL,
		NULL,
		FileDiskThread,
		device_object
		);

	if (!NT_SUCCESS(status))
	{
		IoDeleteDevice(device_object);
		return status;
	}

	status = ObReferenceObjectByHandle(
		thread_handle,
		THREAD_ALL_ACCESS,
		NULL,
		KernelMode,
		&device_extension->thread_pointer,
		NULL
		);

	if (!NT_SUCCESS(status))
	{
		ZwClose(thread_handle);

		device_extension->terminate_thread = TRUE;

		KeSetEvent(
			&device_extension->request_event,
			(KPRIORITY)0,
			FALSE
			);

		IoDeleteDevice(device_object);

		return status;
	}

	ZwClose(thread_handle);

	return STATUS_SUCCESS;
}

NTSTATUS
FileDiskOpenFile(IN PDEVICE_OBJECT   DeviceObject)
{
	PDEVICE_EXTENSION               device_extension;
	NTSTATUS                        status;
	OBJECT_ATTRIBUTES               object_attributes;
	IO_STATUS_BLOCK					status_block;
	FILE_END_OF_FILE_INFORMATION    file_eof;
	device_extension = (PDEVICE_EXTENSION)DeviceObject->DeviceExtension;

	InitializeObjectAttributes(
		&object_attributes,
		&device_extension->DiskInfo.FilePath,
		OBJ_CASE_INSENSITIVE,
		NULL,
		NULL
		);

	status = ZwCreateFile(
		&device_extension->file_handle,
		GENERIC_READ | GENERIC_WRITE,
		&object_attributes,
		&status_block,
		NULL,
		FILE_ATTRIBUTE_NORMAL,
		0,
		FILE_OPEN_IF,
		FILE_NON_DIRECTORY_FILE |
		FILE_RANDOM_ACCESS |
		FILE_NO_INTERMEDIATE_BUFFERING |
		FILE_SYNCHRONOUS_IO_NONALERT,
		NULL,
		0
		);

	file_eof.EndOfFile.QuadPart = device_extension->DiskInfo.DiskGeometryEx.DiskSize.QuadPart;

	status = ZwSetInformationFile(
		device_extension->file_handle,
		&status_block,
		&file_eof,
		sizeof(FILE_END_OF_FILE_INFORMATION),
		FileEndOfFileInformation
		);

	/*if (status == STATUS_SUCCESS)
		device_extension->media_in_device = TRUE;*/
	return status;
}

VOID
FileDiskThread(
IN PVOID Context
)
{
	PDEVICE_OBJECT				device_object;
	PDEVICE_EXTENSION			device_extension;
	PLIST_ENTRY					request;
	PIRP						irp;
	PIO_STACK_LOCATION			io_stack;
	PUCHAR						system_buffer;
	PUCHAR						buffer;
	ULONG						buffer_length;
	LONGLONG					buffer_offset;
	Key							key_encrypt, key_decrypt;
	AES							Aes;
	KeyUnion *					TempBuffer;
	unsigned int				CountOfInterI(0);
	ASSERT(Context != NULL);

#if DBG
	DbgPrint("=Example= FileDiskThread\n");
#endif

	device_object = (PDEVICE_OBJECT)Context;

	device_extension = (PDEVICE_EXTENSION)device_object->DeviceExtension;

	KeSetPriorityThread(KeGetCurrentThread(), LOW_REALTIME_PRIORITY);



	device_extension->DiskInfo.AlgoritmInf.KeyLength = 32;
	memset(device_extension->DiskInfo.AlgoritmInf.Key, '0', 64);
	char strKey[] = "2b7e151628aed2a6abf7158809cf4f3c"; //3c4fcf098815f7aba6d2ae2816157e2b
	for (int i = 0; i < 32; ++i)
		device_extension->DiskInfo.AlgoritmInf.Key[i] = strKey[i];
	//Вычисление количества раундов и инициализация ключа
	unsigned char NR;
	switch (device_extension->DiskInfo.AlgoritmInf.KeyLength >> 1)
	{
	case 16:
		NR = 10;
		break;
	case 24:
		NR = 12;
		break;
	case 32:
		NR = 14;
		break;
	}
	key_encrypt.SetKey(device_extension->DiskInfo.AlgoritmInf.Key, device_extension->DiskInfo.AlgoritmInf.KeyLength >> 3, NR);
	key_decrypt.SetKey(device_extension->DiskInfo.AlgoritmInf.Key, device_extension->DiskInfo.AlgoritmInf.KeyLength >> 3, NR);
	key_decrypt.setDecryptionMod();


	for (;;)
	{
		KeWaitForSingleObject(
			&device_extension->request_event,
			Executive,
			KernelMode,
			FALSE,
			NULL
			);

		if (device_extension->terminate_thread)
		{
			PsTerminateSystemThread(STATUS_SUCCESS);
		}

		FileDiskOpenFile(device_object);

		while (request = ExInterlockedRemoveHeadList(
			&device_extension->list_head,
			&device_extension->list_lock
			))
		{
			irp = CONTAINING_RECORD(request, IRP, Tail.Overlay.ListEntry);
			io_stack = IoGetCurrentIrpStackLocation(irp);
			//Проверка MJ
			if (io_stack->MajorFunction != IRP_MJ_WRITE && io_stack->MajorFunction != IRP_MJ_READ)
			{
				irp->IoStatus.Status = STATUS_DRIVER_INTERNAL_ERROR;
				IoCompleteRequest(irp, IO_NO_INCREMENT);
			}

			if (io_stack->MajorFunction == IRP_MJ_WRITE)
			{
#if DBG
				DbgPrint("=Example= In IRP_MJ_WRITE\n");
#endif
				buffer_length = io_stack->Parameters.Write.Length;
				buffer_offset = io_stack->Parameters.Write.ByteOffset.QuadPart;
			}
			else
			{
#if DBG
				DbgPrint("=Example= In IRP_MJ_READ\n");
#endif
				buffer_length = io_stack->Parameters.Read.Length;
				buffer_offset = io_stack->Parameters.Read.ByteOffset.QuadPart;
			}

			//Проверка offset
			if ((buffer_offset +
				buffer_length) >
				device_extension->DiskInfo.DiskGeometryEx.DiskSize.QuadPart)
			{
				irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
				irp->IoStatus.Information = 0;
				break;
			}

			//Достаем буффер
			system_buffer = (PUCHAR)MmGetSystemAddressForMdlSafe(irp->MdlAddress, NormalPagePriority);
			if (system_buffer == NULL)
			{
				irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
				irp->IoStatus.Information = 0;
				break;
			}

			//Выделяем память под свой буффер
			buffer = (PUCHAR)ExAllocatePool(PagedPool, buffer_length);
			if (buffer == NULL)
			{
				irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
				irp->IoStatus.Information = 0;
				break;
			}

			//Узнаем количество итераций (кол-во блоков данных)
			CountOfInterI = (buffer_length / BLOCK_SIZE);
			TempBuffer = (KeyUnion*)((void*)buffer);

			if (io_stack->MajorFunction == IRP_MJ_WRITE)
			{
				RtlCopyMemory(buffer, system_buffer, io_stack->Parameters.Write.Length);
				Aes.setAlg(&key_encrypt, NR, true); //Настройка АЕС
				for (unsigned int i = 0; i < CountOfInterI; i += 4) //шифруем входной буффер
					Aes.Encrypt(&TempBuffer[i]);
				ZwWriteFile(
					device_extension->file_handle,
					NULL,
					NULL,
					NULL,
					&irp->IoStatus,
					buffer,//MmGetSystemAddressForMdlSafe(irp->MdlAddress, NormalPagePriority),
					io_stack->Parameters.Write.Length,
					&io_stack->Parameters.Write.ByteOffset,
					NULL
					);
			}
			else
			{
				ZwReadFile(
					device_extension->file_handle,
					NULL,
					NULL,
					NULL,
					&irp->IoStatus,
					buffer,
					io_stack->Parameters.Read.Length,
					&io_stack->Parameters.Read.ByteOffset,
					NULL
					);

				Aes.setAlg(&key_decrypt, NR, false); //Настройка АЕС
				for (unsigned int i = 0; i < CountOfInterI; i += 4) //шифруем входной буффер
					Aes.Encrypt(&TempBuffer[i]);
				RtlCopyMemory(system_buffer, buffer, io_stack->Parameters.Read.Length);
			}
			ExFreePool(buffer);
			IoCompleteRequest(irp, (CCHAR)(NT_SUCCESS(irp->IoStatus.Status) ? IO_DISK_INCREMENT : IO_NO_INCREMENT));
		}
		if (device_extension->file_handle != NULL)
			ZwClose(device_extension->file_handle);
	}
}
#pragma code_seg() // end PAGE section

